home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
System
/
SCROLLSOURCE
/
Scroll.c
next >
Wrap
C/C++ Source or Header
|
1987-01-03
|
18KB
|
738 lines
/*********************************************************************
Scroll.c
Programmed by Keith Lambert 1986,87
Compuserve 75076,34
GEnie K.Lambert
OR
3433 Marathon Drive
San Diego, Calif. 92123
Please leave me mail if you have any problems or questions with this
code.
This file is for the LightspeedC development system. If you are not
using this system, you will have to make the neccessary adjustments.
This program will display a Modal Dialog box that contains a
scrollable list of items similiar to the SFGetFile. However this
program does not use any list manager routines.
This program is meant to be an example only, and it might serve as a
template for your own application.
There are no general routines to build a dynamic text list for display
in the dialog. This is left up to the specific application. This example
only uses a list of 20 strings that are in a global array for its text.
This code contains some examples on using filter procedures and
user item procedures for modal dialog boxes.
*********************************************************************/
#include "QuickDraw.h"
#include "MacTypes.h"
#include "FontMgr.h"
#include "WindowMgr.h"
#include "MenuMgr.h"
#include "TextEdit.h"
#include "DialogMgr.h"
#include "EventMgr.h"
#include "DeskMgr.h"
#include "FileMgr.h"
#include "ToolboxUtil.h"
#include "ControlMgr.h"
#include "strings.h"
#include "ctype.h"
#include "types.h"
#include "pascal.h"
#include "Scroll.h"
#define NUMSTRS 20 /* number of strings in dialog */
#define SCROLLDELAY 10000 /* to slow down scrolling a little*/
/* GLOBAL VARIABLES */
EventRecord myEvent;
DialogPtr myWindow; /*ptr to the dialog window*/
WindowPtr EvWindow; /* Event window*/
MenuHandle myMenus[4];
short startValue,endValue; /* scroll bar values */
int MIN = 0 , MAX ; /* min and max values for scroll bar*/
int LinesShow; /* number of lines in scroll box*/
int height; /* line height in text edit record*/
TEHandle theText; /* Handle to the text edit record */
/* the text items in the scrolling dialog */
/* normally you would have to build this list dynamically in your application */
/* but since this is just an example program, let keep it simple. */
char *Strs[] = {
"Airborne\r",
"Archon\r",
"Cyborg\r",
"Gato\r",
"Grid Wars\r",
"Lode Runner\r",
"MacGolf\r",
"Maze Wars+\r",
"Mystery Box\r",
"Orbiter\r",
"Orbquest\r",
"Pinball\r",
"Rogue\r",
"Sargon\r",
"Shanghai\r",
"SkyFox\r",
"Think Ahead+\r",
"Winter Games\r",
"Wizardry\r",
"Zork\r"
} ;
restartProc()
{
ExitToShell();
}
Init()
{
MaxApplZone();
MoreMasters();
MoreMasters();
MoreMasters();
InitGraf(&thePort);
InitFonts();
FlushEvents( everyEvent, 0 );
InitWindows();
InitMenus();
TEInit();
InitDialogs(&restartProc);
InitCursor();
SetUpMenus();
} /* end Init(); */
main()
{
Init();
while (MainEvent()) ;
}
int MainEvent()
{
WindowPtr whichWindow;
SystemTask();
if (GetNextEvent(everyEvent, &myEvent))
{
switch (myEvent.what)
{
case mouseDown:
switch (FindWindow( myEvent.where, &whichWindow ))
{
case inDesk:
SysBeep(10);
break;
case inGoAway:
break;
case inMenuBar:
DoCommand( MenuSelect(myEvent.where) );
case inSysWindow:
SystemClick( &myEvent, whichWindow );
break;
case inDrag:
break;
case inGrow:
break;
case inContent:
checkClick();
break;
default: ;
} /* end switch FindWindow */
break;
case keyDown:
case autoKey:
if ((myEvent.modifiers & cmdKey)) /* menu equivalent ?*/
DoCommand(MenuKey(myEvent.message));
break;
case activateEvt:
break;
case updateEvt: /* Someone said window needs refresh*/
EvWindow = (WindowPtr)myEvent.message; /* Which window?*/
UpdateWind(EvWindow); /* Do the update*/
break;
default:
break;
} /* end of case myEvent.what */
} /* if */
return(1);
}
SetUpMenus()
{
int i;
myMenus[appleM] = GetMenu(appleID);
AddResMenu( myMenus[appleM], 'DRVR' );
myMenus[fileM] = GetMenu(fileID);
myMenus[editM] = GetMenu(editID);
myMenus[dlogM] = GetMenu(DialogID);
for ( (i=appleM); (i<=dlogM); i++ ) InsertMenu(myMenus[i], 0) ;
DrawMenuBar();
}
int DoCommand( mResult )
long mResult;
{
short theItem;
Str255 name;
GrafPtr savePort;
long size,memAvail;
Handle myResHandle,myHandle;
theItem = LoWord( mResult );
switch (HiWord(mResult))
{
case appleID:
if (theItem == 1)
BragAbout();
else
{ /* check memory before opening DA, */
GetItem(myMenus[appleM], theItem, &name);
SetResLoad(FALSE);
myResHandle = GetNamedResource('DRVR',&name);
size = SizeResource(myResHandle) + 3072;
SetResLoad(TRUE);
if((memAvail = CompactMem(size)) > size )
{
GetPort(&savePort);
OpenDeskAcc( &name );
SetPort(savePort);
}
else
SysBeep(5); /* not enough memouy ! */
}
break;
case fileID:
DoFile(theItem);
break;
case editID:
if(SystemEdit(theItem-1));
break;
case DialogID:
DoDialogMenu(theItem);
break;
}
HiliteMenu(0);
return(1);
}
/*============================================================================
Procedure DoFile():
Process all File menu selections here.
============================================================================*/
DoFile(item)
int item;
{
switch(item)
{
case 1: /* QUIT*/
ExitToShell();
break;
}
}
/*============================================================================
Procedure DoDialogMenu():
Process all dialog menu selections here.
============================================================================*/
DoDialogMenu(item)
short item;
{
switch(item)
{
case 1:
DoDialog1();
break;
}
} /* end DoOptMenu() */
/*============================================================================
* Procedure BragAbout:
* Display a dialog box that tells a little about the program.
*============================================================================*/
BragAbout()
{
short itemHit;
GrafPtr savePort;
Handle iconHand;
GetPort(&savePort); /* save the current port*/
myWindow = GetNewDialog(100,0,-1);
SetPort(myWindow);
itemHit = 0;
while(itemHit < 1) /* while not in Ok*/
{
ModalDialog(0,&itemHit); /* wait for mouse click*/
}
DisposDialog(myWindow);
SetPort(savePort);
} /* END BragAbout*/
/*==============================================================================
* Dobold()
* this is the user item procedure to make the thick outline around the default
* button ( assumed to be item 1)
*=============================================================================*/
pascal void Dobold(dlogPtr,item)
DialogPtr dlogPtr;
unsigned short item;
{
unsigned short itype;
Handle ihandle;
Rect irect;
GetDItem(dlogPtr,1,&itype,&ihandle,&irect); /* get the buttons rect */
PenSize(3,3); /* make thick lines */
InsetRect(&irect,-4,-4); /* grow rect a little */
FrameRoundRect(&irect,16,16); /* frame the button now */
PenNormal();
}
/*=============================================================================
* DrawScrollText()
* this the the user item procedure for the scrolling items display. It will
* draw the rectangle around the text and set up text edit record for the
* items in the dialog.
* for some reason I couldn't get the rectangle of the useritem so I could
* draw a rectangle around it, so instead I got the rect of the scrollbar
* and adjusted that rect to the appropriate size.
*============================================================================*/
pascal void DrawScrollText(dlogPtr,item)
DialogPtr dlogPtr;
unsigned short item;
{
register int x;
unsigned short itype;
Handle ihandle;
Rect irect,theRect,viewRect,destRect;
GetDItem(dlogPtr,4,&itype,&ihandle,&irect); /* get the scroll bars rect*/
BlockMove(&irect,&theRect,sizeof(Rect)); /* copy the rect */
theRect.left -= 120; /* adjust left and right sides*/
theRect.right -= 15;
FrameRect(&theRect);
BlockMove(&theRect,&viewRect,sizeof(Rect));
InsetRect(&viewRect,1,1); /* shrink viewRect a little*/
BlockMove(&viewRect,&destRect,sizeof(Rect));
theText = TENew(&destRect,&viewRect); /* setup textedit record*/
height = (*theText)->lineHeight; /* line height in pixels */
/* calculate how many lines will show in the rectangle */
LinesShow = (viewRect.bottom-viewRect.top)/height;
/* set the control max to the number of strings - how many will show */
MAX = (NUMSTRS - LinesShow);
SetCtlMin(ihandle,MIN); /* set the control values */
SetCtlMax(ihandle,MAX);
SetCtlValue(ihandle,MIN);
for(x=0;x<NUMSTRS;x++) /* insert the strings into record*/
{
TEInsert(Strs[x],strlen(Strs[x]),theText);
}
}
/*=============================================================================
* scrollAction()
* this is the action procedure that is used whenever the mouse is held down in
* the scroll bar arrow or page regions. Basically all it does is set the
* control value and then call scrolltext. This procedure executes so fast that
* holding down the mouse in the up or down arrows will scroll by more that one
* line every time so a small dealy has be inserted at the end to adjust it so
* it will scroll only one line.
*============================================================================*/
pascal void scrollAction(theControl,partcode)
ControlHandle theControl;
short partcode;
{
register int x;
startValue = GetCtlValue(theControl);
switch(partcode)
{
case inUpButton:
if(startValue > MIN ) /* to avoid rattling scroll box */
{
SetCtlValue(theControl, startValue - 1 );
ScrollText(theControl);
}
break;
case inDownButton:
if(startValue < MAX )
{
SetCtlValue(theControl, startValue + 1 );
ScrollText(theControl);
}
break;
case inPageUp:
if(startValue > MIN )
{
SetCtlValue(theControl, startValue - (LinesShow-1));
ScrollText(theControl);
}
break;
case inPageDown:
if(startValue < MAX )
{
SetCtlValue(theControl, startValue + (LinesShow-1));
ScrollText(theControl);
}
break;
}
endValue = GetCtlValue(theControl); /* not really used here */
for(x=0;x<SCROLLDELAY;x++); /* slow down scrolling, too fast otherwise */
}
/*==============================================================================
* ScrollText()
* this procedure will scroll the text in the text edit record after the scroll
* bar has been adjusted/
*============================================================================*/
ScrollText(theControl)
ControlHandle theControl;
{
RgnHandle updateRgn;
int scrollValue,scrollDiff,oldScroll,newScroll,ViewTop,DestTop;
ViewTop = (*theText)->viewRect.top;
DestTop = (*theText)->destRect.top;
oldScroll = (ViewTop - DestTop);
scrollValue = GetCtlValue(theControl);
newScroll = (scrollValue * height);
scrollDiff = (oldScroll - newScroll);
if (scrollDiff != 0)
TEScroll(0,scrollDiff,theText);
}
/*============================================================================
* scrollFilter()
* this is the filter proc for the modal dialog. It handles events the way I
* want them. keyDown events will be checked for the RETURN of ENTER keys and be
* treated like a press in the OK button. Pressing the TILDE key will be treated
* like the CANCEL button. All other key presses are ignored.
* mouseDown events are checked to see if they are in the SCROLL BAR or the
* rectangle containg the scrolling text. Other mouse downs are handled by
* ModalDialog.
*===========================================================================*/
pascal char scrollFilter(dp,event,item)
DialogPtr dp;
EventRecord *event;
unsigned short *item;
{
char c,result;
char choosenText[25]; /* storage space for text selected */
Rect irect;
Point eventPoint;
ControlHandle whichControl;
Handle ihandle,TES;
short partcode,bogus,finalTicks;
long startSel,endSel,length;
int DestTop,scrollValue,lineHit,x;
unsigned short itype;
result = FALSE;
if(event->what == keyDown) /* we have a key press */
{
c = event->message & 0x00FF; /* what character is it? */
if(c == 0x0003 || c == 0x000D) /* return or enter keys */
{
GetDItem(dp,1,&itype,&ihandle,&irect);
HiliteControl(ihandle,1); /* pretend user clicked in button*/
Delay(4,finalTicks); /* keep it on screen a moment */
result = TRUE;
*item = 1; /*select the default button */
}
else
{
if(c == 0x0060 || c == 0x007E ) /*use tilde key for Cancel button*/
{ GetDItem(dp,2,&itype,&ihandle,&irect);
HiliteControl(ihandle,1);
Delay(4,finalTicks);
result = TRUE;
*item = 2; /* treat as the cancel button */
}
}
}
else if (event->what == mouseDown) /* mouse was clicked */
{
eventPoint = event->where; /* get the location of click*/
GlobalToLocal(&eventPoint); /* got to make it local */
/* see if the click is inside the scrolling text rectangle */
if (PtInRect( eventPoint, &(**theText).viewRect ))
{
TEActivate(theText);
DestTop = (*theText)->destRect.top;
lineHit = (eventPoint.v - DestTop) / height; /* what line is hit ? */
if(lineHit < 0)
lineHit = 0;
if(lineHit > (NUMSTRS -1))
lineHit = (NUMSTRS -1);
/* now we need to invert the selection that was clicked on*/
/* get the starting and ending point of the string */
startSel = (*theText)->lineStarts[lineHit];
endSel = (*theText)->lineStarts[(lineHit+1)];
TESetSelect(startSel,endSel,theText); /* set and invert selection */
ZeroScrap(); /* clear out scrap area */
TECopy(theText); /* copy selection to textedit scrap */
TES = TEScrapHandle(); /* get a handle to text just copied */
length = TEGetScrapLen(); /* get length of text copied */
/* NOTE: the text that we have a handle to is just text. It is not*/
/* a pascal string or a C string, just text. Therefore we cannot */
/* use it as a argument to SetIText() because it expects a pointer*/
/* to a pascal Str255 type not just a pointer to char. To get around*/
/* this we will copy this text into our own storage space and then */
/* add a null marker to the end. Thus making it a C string. Then we*/
/* call CtoPstr() with the string and then pass it to SetIText. */
HLock(TES);
strcpy(choosenText,*TES); /* copy text into out storage */
*(choosenText + length) = '\0'; /* add a null to mark end of string*/
CtoPstr(choosenText); /* make it a pascal string */
GetDItem(dp,7,&itype,&ihandle,&irect); /* get the handel to item 7*/
/* set item 7 to the text that was selected */
SetIText(ihandle,choosenText);
PtoCstr(choosenText); /* change string back to C format */
HUnlock(TES);
result = TRUE;
} /* end if ptinrect */
else /* see where mouse click was */
{
partcode = FindControl(eventPoint,dp,&whichControl);
if(partcode == inThumb)
{
startValue = GetCtlValue(whichControl);
bogus = TrackControl(whichControl,eventPoint,0);
endValue = GetCtlValue(whichControl);
ScrollText(whichControl);
result = TRUE;
}
/* only watch events in the scroll bar */
else if(partcode >= inUpButton)
{
bogus = TrackControl(whichControl,eventPoint,&scrollAction);
result = TRUE;
}
}
} /* end else if (event->what == mouseDown) */
return(result);
}
/*=============================================================================
* ProcedureDoDialog1()
* this is where all the dialog routines are set up.
* For this Dialog I will use two user items. One for the bold outline on
* the default button and the other for the scrolling text and its rect.
* I will also be using a filter proc to handle the modal dialog events the
* way I want them.
*===========================================================================*/
DoDialog1()
{
short itemHit,itype,x;
GrafPtr savePort;
Rect irect;
Handle ihandle;
char flag;
GetPort(&savePort); /* save the current port*/
myWindow = GetNewDialog(500,0,-1);
/* set up the 2 user items for the dialog */
SetDItem(myWindow,5,userItem,&DrawScrollText,&irect);
SetDItem(myWindow,6,userItem,&Dobold,&irect);
SetPort(myWindow); /* dialog is current port*/
ShowWindow(myWindow);
flag = TRUE;
while(flag)
{
ModalDialog(&scrollFilter,&itemHit); /* use a filter routine*/
switch(itemHit)
{
case 1: /* OK*/
/* insert ok procedures here */
flag = FALSE; /* Done with dialog*/
break;
case 2: /* CANCEL*/
/* insert cancel procedures here */
flag = FALSE;
break;
} /* END itemHit switch*/
} /* END while TRUE*/
TEDispose(theText); /* get rid of text edit */
DisposDialog(myWindow); /* get rid of Dialog */
SetPort(savePort); /* restore old port*/
} /* END */
/*=========================================================================*/
UpdateWind(wp)
WindowPtr wp;
{
BeginUpdate(wp);
SetPort(wp);
EndUpdate(wp);
}
/*=========================================================================*/
/*=========================================================================*/
checkClick()
{
SysBeep(1);
} /* end of checkClick */